import { Injectable } from "@nestjs/common";
import { LoggerService } from "@/common/logger/logger.service";
import { UserService } from "../user/user.service";
import { ConfigService } from "@nestjs/config";
import { RedisService } from "@/common/redis/redis.service";
import { LoginAccountDto } from "./dto/login-account.dto";
import { LoginEmailDto } from "./dto/login-email.dto";
import type { Request } from "express";
import { getClientIp } from "@/utils/request.info";
import { JwtPayloadInterface } from "@/common/interfaces";
import { plainToClass } from "class-transformer";
import { ExportLoginDto } from "./dto/export-login.dto";
import { JwtService } from "@nestjs/jwt";
import { EnvEnum } from "@/common/enums/env.enum";
import { RedisKeyEnum } from "@/common/enums/redis-key.enum";
import { handleError } from "@/utils/handle.error";
import { TUser } from "@/@types/common";

@Injectable()
export class AuthService {
	constructor(
		private readonly logger: LoggerService,
		private readonly userService: UserService,
		private readonly configService: ConfigService,
		private readonly redisService: RedisService,
		private readonly jwtService: JwtService,
	) {
		this.logger.setContext(AuthService.name);
	}

	/** 登录逻辑 */
	async login(loginAccountDto: LoginAccountDto | LoginEmailDto, req: Request) {
		try {
			this.logger.log(`${this.login.name} was called`);
			// 1. 验证用户信息
			let user;
			if ("name" in loginAccountDto) {
				user = await this.userService.validateUserByPwd(
					loginAccountDto.name,
					loginAccountDto.password,
				);
			} else if ("email" in loginAccountDto) {
				user = await this.userService.validateUserByEmail(
					loginAccountDto.email,
					loginAccountDto.code,
				);
			}
			const ip = getClientIp(req);
			// 2. 记录用户登录ip
			this.userService.recordUserIp(user.id, ip);

			this.userService.updateUser({ ...user, openid: loginAccountDto.openid });

			// 3. 生成token
			const { accessToken, refreshToken } = this.getAccessAndRefreshToken(
				user.id,
				user.name,
				user.email,
			);

			this.redisService._setex(
				RedisKeyEnum.LoginKey + user.id,
				60 * 60,
				accessToken,
			);

			return {
				...user,
				accessToken,
				refreshToken,
			};
		} catch (error) {
			handleError(this.logger, error, {
				common: "登录失败",
			});
		}
	}

	/** 刷新token */
	async refreshToken(id: number) {
		try {
			this.logger.log(`${this.refreshToken.name} was called`);
			const user = await this.userService.findUserById(id);
			const { accessToken, refreshToken } = this.getAccessAndRefreshToken(
				user.id,
				user.name,
				user.email,
			);
			this.redisService._setex(
				RedisKeyEnum.LoginKey + user.id,
				60 * 60,
				accessToken,
			);
			return {
				accessToken,
				refreshToken,
			};
		} catch (error) {
			handleError(this.logger, error, {
				common: "刷新token失败",
			});
		}
	}

	/** 退出登录 */
	async logout(req: Request) {
		try {
			this.logger.log(`${this.logout.name} was called`);
			const { id, name, email } = req.user as TUser;
			const res = await this.redisService._delKeysContainStr(
				RedisKeyEnum.LoginKey + id,
			);
			console.log("打印***res", res);
			return res;
		} catch (error) {
			handleError(this.logger, error, {
				common: "退出登录失败",
			});
		}
	}

	/** 获取access_token 和refresh_token */
	getAccessAndRefreshToken(id: number, name: string, email: string) {
		this.logger.log(`${this.getAccessAndRefreshToken.name} was called`);
		const payload: JwtPayloadInterface = { id, name, email };
		return plainToClass(ExportLoginDto, {
			accessToken: this.jwtService.sign(payload, {
				expiresIn: this.configService.get(EnvEnum.JWT_ACCESS_TOKEN_EXPIRES_IN),
			}),
			refreshToken: this.jwtService.sign(
				{ id },
				{
					expiresIn: this.configService.get(
						EnvEnum.JWT_REFRESH_TOKEN_EXPIRES_IN,
					),
				},
			),
		});
	}
}
